/*
 *  Description: WINUSB
 *  Version: V1.00
 *  Author: boat xu
 *  Email: xifengzui@outlook.com
 *  Date: 2020-07-22 14:20:21
 *  LastEditTime: 2020-07-22 14:41:12
 */ 
#include "CH552.H"
#include "Debug.H"
#include "types.h"
#include "string.h"
#include "stdio.h"
#define Fullspeed 1
#define WINUSB 1
#define THIS_ENDP0_SIZE 64
#define WIRELESS_SIZE   64


UINT8X Ep0Buffer[THIS_ENDP0_SIZE] _at_ 0x0000;  //端点0 OUT&IN缓冲区，必须是偶地址

//100,140,180,1C0
UINT8X Ep2BufferO[4 * THIS_ENDP0_SIZE] _at_ 0x0100; //端点2 OUT双缓冲区,必须是偶地址
UINT8X Ep2BufferOiCnt[4] _at_ 0x340;//接收的长度计数器
//200,240,280,2C0
UINT8X Ep3BufferI[4 * THIS_ENDP0_SIZE] _at_ 0x0200; //端点3 IN双缓冲区,必须是偶地址
UINT8X WirelessRecvBuf[WIRELESS_SIZE] _at_ 0x300;
UINT8X Ep3BufferIiCnt[4] _at_ 0x344;//发送的长度计数器

UINT8I Ep2Oi, Ep2Oo;            //OUT 索引 host向从机发送数据
UINT8I Ep3Ii, Ep3Io;            //IN 索引 从机向host发送数据
UINT8I WlsI,WlsO;
PUINT8 pDescr; //USB配置标志
UINT8I Endp3Busy = 0;
UINT8I SetupReq, SetupLen, Ready, Count, UsbConfig;
#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)

#if (WINUSB == 1)
/*
这个表详细的阐述了描述符的类型
#define USB_DESC_TYPE_DEVICE 0x01U
#define USB_DESC_TYPE_CONFIGURATION 0x02U
#define USB_DESC_TYPE_STRING 0x03U
#define USB_DESC_TYPE_INTERFACE 0x04U
#define USB_DESC_TYPE_ENDPOINT 0x05U
#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06U
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07U
#define USB_DESC_TYPE_BOS 0x0FU

*/
//设备描述符 
//详解 0x12 代表有18个字节
// 0x01描述符类型 固定为0x01
// 0x10 0x02设备使用的USB协议版本210
// 0xEF 类代码 0x01~0xFE为标准代码，这里的EF代表杂类
// 0x02 子类代码
// 0x01 协议代码
// THIS_ENDP0_SIZE 端点0的最大长度
// 0x28 0x0D 供应商ID  就是VID
// 0x04 0x02 产品ID 就是PID0204
//  0x00 0x01 设备版本号 就是1.00版本
// 0x01 供应商字符串描述索引 
//0x02 产品字符描述字符串索引 
// 0x03 产品序列号描述符索引 
// 0x01 所支持的配置数 
//18 7c 05 50 Alienware Corporation LED controller
//1a 86 e008 HID-based serial adapater
//0424 4940
UINT8C DevDesc[] = 
{
    0x12, 0x01, 0x10, 0x02, 0xEF, 0x02, 0x01, THIS_ENDP0_SIZE,
    0x86, 0x1a, 0xfb, 0xe1, 0x00, 0x01, 0x01, 0x02,
    0x03, 0x01
};

//配置描述符
//0x09 描述符长度
//0x02 描述符类型编号
//0x0020 此配置所有返回长度大小 32字节
//0x01 接口数量 1
//0x01 set configuration 命令需要的参数值
//0x00 描述该配置的字符串索引值  //在标准请求里，可以看到对应的索引对应的字符串
//0x80 供电模式的选择
//0xfa 设备从总线题曲的最大电流

//接口描述符
//0x09 接口长度
//描述符类型编号 0x04
//0x00 接口的编号
//0x00 备用的接口描述符编号
//0x02 该接口使用的端点数
//0xff 接口类型
//0x00 接口子类型
//0x00 接口遵循的协议
//0x04 描述该接口的字符串索引值

//端点描述符
//0x07长度
//0x05描述符类型编号???
//0x02 和 0x82 端点地址???

/*

Bit 3…0: 端点数量
Bit 6…4: 保留，默认为0
Bit 7:如果是控制端点可以忽略，否则一般表示数据传输方向
    0 = OUT endpoint
    1 = IN endpoint
*/

//0x02 端点属性
/*
Bits 1..0: Transfer Type，传输类型
    00 = Control-控制传输
    01 = Isochronous-等时传输
    10 = Bulk-批量传输
    11 = Interrupt-中断传输
*/
//0x0040端点最大长度
// 查询时间 
UINT8C CfgDesc[] =
{
    0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0xfa, //配置描述符
    0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x04, //接口描述符
    
    0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, //端点描述符
    0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
};
#else
#Err no USB interface define
#endif

UINT16I USB_STATUS = 0;
// 语言描述符
//0x04 字符串长度
//0x03 描述符类型
//0x09 0x04 字符串
UINT8C MyLangDescr[] = {0x04, 0x03, 0x09, 0x04};
// 厂家信息:
UINT8C MyManuInfo[] = {16, 0x03, 'Q', 0x00, 'i', 0x00, 'n', 0x00, 'H', 0x00, 'e', 0x00, 'n', 0x00, 'g', 0x00};
UINT8C MyProdInfo[] =
{
    30,
    0x03,
    'S', 0,'F', 0, '-', 0, 'T', 0, 'r', 0, 'a', 0, 'n', 0, 's', 0, 
	  'm', 0,'i', 0,'t',0,'t',0,'e',0,'r',0,
};
// 序列号: 0001A0000000
UINT8C MySerNumber[] = 
{
    0x1A,
    0x03,
    '2', 0, '0', 0, '2', 0, '0', 0, '0', 0, '6', 0, '2', 0, '2', 0,
    '1', 0, '6', 0, '4', 0, '5', 0
};
// 接口: CMSIS-DAP
UINT8C MyInterface[] =
{
    30,
    0x03,
    'S', 0, 'F', 0, '-', 0, 'T', 0, 'r', 0, 'a', 0, 'n', 0, 's', 0, 'm', 0, 'i', 0, 't', 0, 't', 0,'e', 0,'r', 0
};

UINT8C USB_BOSDescriptor[] =
{
    0x05,                                      /* bLength */
    0x0F,                                      /* bDescriptorType */
    0x28, 0x00,                                /* wTotalLength */
    0x02,                                      /* bNumDeviceCaps */
    0x07, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,
    0x1C,                                      /* bLength */
    0x10,                                      /* bDescriptorType */
    0x05,                                      /* bDevCapabilityType */
    0x00,                                      /* bReserved */
    0xDF, 0x60, 0xDD, 0xD8,                    /* PlatformCapabilityUUID */
    0x89, 0x45, 0xC7, 0x4C,
    0x9C, 0xD2, 0x65, 0x9D,
    0x9E, 0x64, 0x8A, 0x9F,
    0x00, 0x00, 0x03, 0x06,    /* >= Win 8.1 *//* dwWindowsVersion*/
    0xA2, 0x00,                                /* wDescriptorSetTotalLength */
    0x20,                                      /* bVendorCode */
    0x00                                       /* bAltEnumCode */
};

UINT8C WINUSB_Descriptor[] =
{
   0x0A, 0x00,                                 /* wLength */
    0x00, 0x00,                                 /* wDescriptorType */
    0x00, 0x00, 0x03, 0x06,                     /* dwWindowsVersion*/
    0xA2, 0x00,                                 /* wDescriptorSetTotalLength */
    /* ... 
    0x08, 0x00,
    0x02, 0x00,
    0x00, 0x00,
    0xA0, 0x00,
    ... */
    0x14, 0x00,                                 /* wLength */
    0x03, 0x00,                                 /* wDescriptorType */
    'W', 'I', 'N', 'U', 'S', 'B', 0, 0,         /* CompatibleId*/
    0, 0, 0, 0, 0, 0, 0, 0,                     /* SubCompatibleId*/
    0x84, 0x00,                                 /* wLength */
    0x04, 0x00,                                 /* wDescriptorType */
    0x07, 0x00,                                 /* wPropertyDataType */
    0x2A, 0x00,                                 /* wPropertyNameLength */
    'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
    'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
    'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
    0x50, 0x00,                                 /* wPropertyDataLength */
    '{', 0,
    '2', 0, '2', 0, '1', 0, '6', 0, '1', 0, 'e', 0, 'a', 0, 'c', 0, '-', 0,
    '2', 0, 'c', 0, 'e', 0, 'd', 0, '-', 0,
    '4', 0, '2', 0, '4', 0, '9', 0, '-', 0,
    'a', 0, '4', 0, '3', 0, 'e', 0, '-',
    0, 'e', 0, 'a', 0, 'f', 0, '5', 0, '8', 0, '7', 0, 'c', 0, 'd', 0, '6', 0, 'e', 0, 'b', 0, '2', 0,
    '}', 0, 0, 0, 0, 0,
};

UsbOnRecvData_Types UsbOnRecvData = 0;
/*******************************************************************************
* Function Name  : USBDeviceInit()
* Description    : USB设备模式配置,设备模式启动，收发端点配置，中断开启
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USBDeviceInit()
{
    IE_USB = 0;
    USB_CTRL = 0x00;        // 先设定USB设备模式
    UDEV_CTRL = bUD_PD_DIS; // 禁止DP/DM下拉电阻
#ifndef Fullspeed
    UDEV_CTRL |= bUD_LOW_SPEED; //选择低速1.5M模式
    USB_CTRL |= bUC_LOW_SPEED;
#else
    UDEV_CTRL &= ~bUD_LOW_SPEED; //选择全速12M模式，默认方式
    USB_CTRL &= ~bUC_LOW_SPEED;
#endif
    UEP0_DMA = Ep0Buffer;                                      //端点0数据传输地址
    UEP4_1_MOD &= ~(bUEP4_RX_EN | bUEP4_TX_EN);                //端点0单64字节收发缓冲区
    UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;                 //OUT事务返回ACK，IN事务返回NAK
    UEP2_DMA = Ep2BufferO;                                     //端点2数据传输地址
    UEP3_DMA = Ep3BufferI;                                     //端点2数据传输地址
    UEP2_3_MOD |= (bUEP3_TX_EN | bUEP2_RX_EN);                   //端点2发送接收使能
    UEP2_3_MOD &= ~(bUEP2_BUF_MOD | bUEP3_BUF_MOD);            //端点2收发各64字节缓冲区
    UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK; //端点2自动翻转同步标志位，IN事务返回NAK，OUT返回ACK
    UEP3_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_NAK;//端点3自动翻转同步标志位，IN事务返回NAK，OUT返回NACK

    USB_DEV_AD = 0x00;
    USB_CTRL |= bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; // 启动USB设备及DMA，在中断期间中断标志未清除前自动返回NAK
    UDEV_CTRL |= bUD_PORT_EN;                              // 允许USB端口
    USB_INT_FG = 0xFF;                                     // 清中断标志
    USB_INT_EN = bUIE_SUSPEND | bUIE_TRANSFER | bUIE_BUS_RST;
    IE_USB = 1;
}

/*******************************************************************************
* Function Name  : DeviceInterrupt()
* Description    : CH559USB中断处理函数
*******************************************************************************/
void DeviceInterrupt(void) interrupt INT_NO_USB using 1 //USB中断服务程序,使用寄存器组1
{
    UINT8 len;
    if (UIF_TRANSFER) //USB传输完成标志
    {
        switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
        {
        case UIS_TOKEN_OUT | 2: //endpoint 2# 端点批量下传
            if (U_TOG_OK)         // 不同步的数据包将丢弃
            {
                Ep2BufferOiCnt[Ep2Oi>>6] = USB_RX_LEN;
                Ep2Oi += 64;
                UEP2_DMA_L = Ep2Oi;
            }
            break;

        case UIS_TOKEN_IN | 3: //endpoint 3# 端点批量上传
            Endp3Busy = 0;
            UEP3_T_LEN = 0;      //预使用发送长度一定要清空
            UEP3_CTRL = UEP3_CTRL & ~MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
            break;
        case UIS_TOKEN_SETUP | 0: //SETUP事务
            len = USB_RX_LEN;
            if (len == (sizeof(USB_SETUP_REQ)))
            {
                SetupLen = UsbSetupBuf->wLengthL;
                if (UsbSetupBuf->wLengthH)
                    SetupLen = 0xFF; // 限制总长度
                len = 0;           // 默认为成功并且上传0长度
                SetupReq = UsbSetupBuf->bRequest;
                switch (UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK)
                {
                case USB_REQ_TYP_STANDARD:
                    switch (SetupReq) //请求码
                    {
                    case USB_GET_DESCRIPTOR:
                        switch (UsbSetupBuf->wValueH)
                        {
                        case 1:             //设备描述符
                            pDescr = DevDesc; //把设备描述符送到要发送的缓冲区
                            len = sizeof(DevDesc);
                            break;
                        case 2:             //配置描述符
                            pDescr = CfgDesc; //把设备描述符送到要发送的缓冲区
                            len = sizeof(CfgDesc);
                            break;
                        case 3: // 字符串描述符
                            switch (UsbSetupBuf->wValueL)
                            {
                            case 0:
                                pDescr = (PUINT8)(&MyLangDescr[0]);
                                len = sizeof(MyLangDescr);
                                break;
                            case 1:
                                pDescr = (PUINT8)(&MyManuInfo[0]);
                                len = sizeof(MyManuInfo);
                                break;
                            case 2:
                                pDescr = (PUINT8)(&MyProdInfo[0]);
                                len = sizeof(MyProdInfo);
                                break;
                            case 3:
                                pDescr = (PUINT8)(&MySerNumber[0]);
                                len = sizeof(MySerNumber);
                                break;
                            case 4:
                                pDescr = (PUINT8)(&MyInterface[0]);
                                len = sizeof(MyInterface);
                                break;
                            default:
                                len = 0xFF; // 不支持的字符串描述符
                                break;
                            }
                            break;
                        case 15:
                            pDescr = (PUINT8)(&USB_BOSDescriptor[0]);
                            len = sizeof(USB_BOSDescriptor);
                            break;
                        default:
                            len = 0xff; //不支持的命令或者出错
                            break;
                        }
                        break;
                    case USB_SET_ADDRESS:
                        SetupLen = UsbSetupBuf->wValueL; //暂存USB设备地址
                        break;
                    case USB_GET_CONFIGURATION:
                        Ep0Buffer[0] = UsbConfig;
                        if (SetupLen >= 1)
                        {
                            len = 1;
                        }
                        break;
                    case USB_SET_CONFIGURATION:
                        UsbConfig = UsbSetupBuf->wValueL;
                        if (UsbConfig)
                        {
                            Ready = 1; //set config命令一般代表usb枚举完成的标志
                        }
                        break;
                    case 0x0A:
                        break;
                    case USB_CLEAR_FEATURE:                                                       //Clear Feature
                        if ((UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) // 端点
                        {
                            switch (UsbSetupBuf->wIndexL)
                            {
                            case 0x82:
                                UEP2_CTRL = UEP2_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES) | UEP_T_RES_NAK;
                                break;
                            case 0x81:
                                UEP1_CTRL = UEP1_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES) | UEP_T_RES_NAK;
                                break;
                            case 0x02:
                                UEP2_CTRL = UEP2_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES) | UEP_R_RES_ACK;
                                break;
                            default:
                                len = 0xFF; // 不支持的端点
                                break;
                            }
                        }
                        else
                        {
                            len = 0xFF; // 不是端点不支持
                        }
                        break;
                    case USB_SET_FEATURE:                             /* Set Feature */
                        if ((UsbSetupBuf->bRequestType & 0x1F) == 0x00) /* 设置设备 */
                        {
                            if ((((UINT16)UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == 0x01)
                            {
                                if (CfgDesc[7] & 0x20)
                                {
                                    /* 设置唤醒使能标志 */
                                }
                                else
                                {
                                    len = 0xFF; /* 操作失败 */
                                }
                            }
                            else
                            {
                                len = 0xFF; /* 操作失败 */
                            }
                        }
                        else if ((UsbSetupBuf->bRequestType & 0x1F) == 0x02) /* 设置端点 */
                        {
                            if ((((UINT16)UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == 0x00)
                            {
                                switch (((UINT16)UsbSetupBuf->wIndexH << 8) | UsbSetupBuf->wIndexL)
                                {
                                case 0x82:
                                    UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL; /* 设置端点2 IN STALL */
                                    break;
                                case 0x02:
                                    UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL; /* 设置端点2 OUT Stall */
                                    break;
                                case 0x81:
                                    UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL; /* 设置端点1 IN STALL */
                                    break;
                                default:
                                    len = 0xFF; /* 操作失败 */
                                    break;
                                }
                            }
                            else
                            {
                                len = 0xFF; /* 操作失败 */
                            }
                        }
                        else
                        {
                            len = 0xFF; /* 操作失败 */
                        }
                        break;
                    case USB_GET_STATUS:
                        pDescr = (PUINT8)&USB_STATUS;
                        if (SetupLen >= 2)
                        {
                            len = 2;
                        }
                        else
                        {
                            len = SetupLen;
                        }
                        break;
                    default:
                        len = 0xff; //操作失败
                        break;
                    }

                    break;
                case USB_REQ_TYP_VENDOR:
                    if ((UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE)
                    {
                        switch (SetupReq)
                        {
                        case 0x20:                         //GetReport
                            if (UsbSetupBuf->wIndexL == 0x07)
                            {
                                pDescr = WINUSB_Descriptor; //把设备描述符送到要发送的缓冲区
                                len = sizeof(WINUSB_Descriptor);
                            }
                            break;
                        default:
                            len = 0xFF; /*命令不支持*/
                            break;
                        }
                    }
                    break;
                default:
                    len = 0xFF;
                    break;
                }
                if (len != 0 && len != 0xFF)
                {
                    if (SetupLen > len)
                    {
                        SetupLen = len; //限制总长度
                    }
                    len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen; //本次传输长度
                    memcpy(Ep0Buffer, pDescr, len);                                 //加载上传数据
                    SetupLen -= len;
                    pDescr += len;
                }
            }
            else
            {
                len = 0xff; //包长度错误
            }
            if (len == 0xff)
            {
                SetupReq = 0xFF;
                UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; //STALL
            }
            else if (len <= THIS_ENDP0_SIZE) //上传数据或者状态阶段返回0长度包
            {
                UEP0_T_LEN = len;
                UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; //默认数据包是DATA1，返回应答ACK
            }
            else
            {
                UEP0_T_LEN = 0;                                                      //虽然尚未到状态阶段，但是提前预置上传0长度数据包以防主机提前进入状态阶段
                UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; //默认数据包是DATA1,返回应答ACK
            }
            break;
        case UIS_TOKEN_IN | 0: //endpoint0 IN
            switch (SetupReq)
            {
            case USB_GET_DESCRIPTOR:
            case 0x20:
                len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen; //本次传输长度
                memcpy(Ep0Buffer, pDescr, len);                                 //加载上传数据
                SetupLen -= len;
                pDescr += len;
                UEP0_T_LEN = len;
                UEP0_CTRL ^= bUEP_T_TOG; //同步标志位翻转
                break;
            case USB_SET_ADDRESS:
                USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
                UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
                break;
            default:
                UEP0_T_LEN = 0; //状态阶段完成中断或者是强制上传0长度数据包结束控制传输
                UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
                break;
            }
            break;
        case UIS_TOKEN_OUT | 0: // endpoint0 OUT
            len = USB_RX_LEN;
            if (SetupReq == 0x09)
            {
                if (Ep0Buffer[0])
                {
                }
                else if (Ep0Buffer[0] == 0)
                {
                }
            }
            UEP0_CTRL ^= bUEP_R_TOG; //同步标志位翻转
            break;
        default:
            break;
        }
        UIF_TRANSFER = 0; //写0清空中断
    }
    if (UIF_BUS_RST) //设备模式USB总线复位中断
    {
        UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
        UEP1_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK;
        UEP2_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
        USB_DEV_AD = 0x00;
        UIF_SUSPEND = 0;
        UIF_TRANSFER = 0;
        Endp3Busy = 0;
        UIF_BUS_RST = 0; //清中断标志
    }
    if (UIF_SUSPEND) //USB总线挂起/唤醒完成
    {
        UIF_SUSPEND = 0;
        if (USB_MIS_ST & bUMS_SUSPEND) //挂起
        {
        }
    }
    else
    {
        //意外的中断,不可能发生的情况
        USB_INT_FG = 0xFF; //清中断标志
    }
}

/**
 * 每次都会从发送缓冲区拿去64字节，但是给出的len则是USB真实会发送的数据字节，并且对每个发送长度进行规划,超过4个以后会循环覆盖之前的RAM
*/
void *GetUsbSendBuffer_Begin() 
{
    void *ptr = 0;
    ptr = (&(Ep3BufferI[Ep3Ii]));
    return ptr;
}

void GetUsbSendBuffer_End(UINT8 len)
{
    if(len!=0)
    {
        Ep3BufferIiCnt[Ep3Ii>>6] = len;
        Ep3Ii+=64;
    }
}
#if 0
void UsbSendOneBulkPre(unsigned char *databuf,unsigned char dataLen)
{
    Ep3BufferIiCnt[Ep3Ii>>6] = dataLen;
    while(dataLen)
    {
        dataLen--;
        Ep3BufferI[Ep3Ii + dataLen] = databuf[dataLen];
    }
    Ep3Ii+=64;
}
#endif



void usb_init(void)
{
    USBDeviceInit(); //USB设备模式初始化
    Ep2Oi = 0;
    Ep2Oo = 0;
    Ep3Ii = 0;
    Ep3Io = 0;
    WlsI  = 0;
    WlsO  = 0;
    EA = 1;          //允许单片机中断
    UEP1_T_LEN = 0;  //预使用发送长度一定要清空
    UEP2_T_LEN = 0;  //预使用发送长度一定要清空
    Ready = 0;
    Endp3Busy = 0;
    //LED 推挽输出
    while (!UsbConfig) {};
}

void usb_do(void)
{
        if(Ep2Oi != Ep2Oo)
        {
            //ledToggle();		
			//Ep2BufferO[Ep2Oo] = 0xAA;
            //memcpy(&Ep3BufferI[Ep3Ii],&Ep2BufferO[Ep2Oo],64);
            if(UsbOnRecvData != 0)
            {
                UsbOnRecvData(&Ep2BufferO[Ep2Oo],Ep2BufferOiCnt[Ep2Oo>>6]);
            }
            Ep2Oo += 64;
        }

        if ((Endp3Busy != 1) && (Ep3Ii != Ep3Io))
        {
            Endp3Busy = 1;
            UEP3_T_LEN = Ep3BufferIiCnt[Ep3Io>>6];//Ep3Icnt;//Ep3Io>>6];
            UEP3_DMA_L = Ep3Io;
            UEP3_CTRL = UEP3_CTRL & ~MASK_UEP_T_RES | UEP_T_RES_ACK; //有数据时上传数据并应答ACK
            Ep3Io += 64;
        }
}